import {
  debug,
  confirmClean,
  forceClean,
  speedOnly,
  features,
} from "./buildConfig.mts";
import { logger, speed } from "./logger.mts";
import {
  cleanValue,
  defaultValues,
  errorListen,
  getComment,
  getSavedHosts,
  getUserConfig,
  gmMenu,
  gmReport,
  runOnce,
  values,
} from "./gmBridge.mts";
import { readCss } from "./presave.mts";
import { cleanRules, switchDisabledStat } from "./actions.mts";
import { performUpdate, makeInitMenu } from "./update.mts";
import { styleApply, parseRules, initRules, getCustomHash } from "./parse.mts";
import { data } from "./globalData.mts";

async function main() {
  if (!location.protocol.startsWith("http")) return;
  // 初始化 data
  const blacks = await values.black();
  data.disabled = features.menu
    ? (blacks?.includes(location.hostname) ?? false)
    : false;
  data.preset = await getUserConfig("css");
  data.timeout = await getUserConfig("timeout");
  data.tryCount = await getUserConfig("tryCount");
  data.tryTimeout = await getUserConfig("tryTimeout");
  data.headTimeout = await getUserConfig("headTimeout");
  data.customRules = await getUserConfig("rules");
  data.autoCleanSize = await getUserConfig("autoCleanSize");
  if (features.fromComment) data.customRules += "\n" + getComment();
  if (debug && !speedOnly) {
    logger("count", "执行次数");
    logger("info", "iframe: ", data.isFrame);
    gmReport();
    logger("data", {
      crules: data.customRules,
      preset: data.preset,
      timeout: data.timeout,
      htimeout: data.headTimeout,
      tcount: data.tryCount,
      tout: data.tryTimeout,
      cleansize: data.autoCleanSize,
    });
    if (forceClean) await cleanValue();
    if (confirmClean) await cleanRules();
    const blackss = await values.black();
    const rules = await values.rules();
    const time = await values.time();
    const hash = await values.hash();
    const etags = await values.etags();
    const brules = await values.brules();
    logger("data", {
      black: blackss?.join(","),
      rules: rules
        ? Object.keys(rules ?? defaultValues.rules).join(",")
        : rules,
      time,
      hash,
      etags: etags
        ? Object.keys(etags ?? defaultValues.etags).join(",")
        : etags,
      hides: brules?.length,
    });
    logger("info", "禁用: ", location.hostname, data.disabled);
  }
  let finish = false;
  if (features.menu) await gmMenu("disable", switchDisabledStat);
  if (features.menu && features.fromValues && data.disabled) {
    await gmMenu("count", cleanRules);
    return;
  }
  if (features.presave && (await getSavedHosts(location.hostname))) {
    await readCss();
  }
  const hashNow = features.customHash
    ? await getCustomHash(false)
    : defaultValues.hash;
  const hashStored = await values.hash();
  debug &&
    !speedOnly &&
    logger(
      "color",
      "应用预存 ?",
      "royalblue",
      await getSavedHosts(location.hostname),
      data.saved,
      hashStored === hashNow,
    );
  saved: {
    if (features.menu) await makeInitMenu();
    if (features.customHash && hashStored !== hashNow) {
      await getCustomHash(true);
      if (features.menu) await initRules(true);
      break saved;
    }
    if (features.presave && data.saved) {
      await styleApply();
      if (!data.update) break saved;
    }
    await initRules(false);
    if (data.receivedRules.length === 0) {
      if (features.update) await performUpdate(true);
      await gmMenu("count");
      if (features.menu) await initRules(true);
      finish = true;
    } else await parseRules();
  }
  if (features.update && !finish) {
    try {
      await performUpdate(false);
    } catch (error) {
      console.warn("iframe:", location.href, "取消更新:", error);
    }
  }
}

if (debug) {
  if (!speedOnly) errorListen();
  try {
    speed("run", "start");
    speed("run2", "start");
    speed("run3", "start");
    runOnce(data.mutex, main)
      .then(() => {
        speed("run", "end");
      })
      .catch(() => {
        speed("run", "end");
      });
  } catch (error) {
    logger("error", (error as ErrorEvent).message ?? (error as string));
  }
} else void runOnce(data.mutex, main);
